//
//  mcast_client_process.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2013-2014 Razvan Coca (razvan dot coca at  gmail dot com)
// This is mostly generated code. Generator is distributed under GPL. Edit it to suit your needs.
// 


#ifndef mcast_client_process_hpp
#define mcast_client_process_hpp
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>

#include "patterns/command.hpp"
#include "patterns/handlers.hpp"

#include "logging/logging.hpp"

namespace pcmd=patterns::command;
namespace phdl=patterns::handlers;
namespace ba=boost::asio;
namespace bs=boost::system;
namespace bt=boost::posix_time;

#include "components/defs/util_types.hpp"
#include "components/defs/client_processor.hpp"
#include "components/utils/linear_flight_timer.hpp"
#include "components/protocol/client_service_request.hpp"
#include "components/protocol/recv_service_replies.hpp"
#include "components/defs/handler_types.hpp"

namespace components{
namespace service{



class mcast_client_process :public boost::enable_shared_from_this<mcast_client_process>, private boost::noncopyable
{
private:
    std::string name_;

    ba::io_service& ios_;

    udp_endpoint_t& local_if_;

    udp_endpoint_t& mgroup_;

    int ttl_;

    crypto_buf_t& iv_;

    crypto_buf_t& key_;

    stats_message_client_processor& message_processor_;

    ba::ip::udp::socket msocket_;

    boost::shared_ptr<components::protocol::recv_service_replies> recv_service_replies_;

    boost::shared_ptr<components::protocol::client_service_request> client_service_request_;

    boost::shared_ptr<components::utils::linear_flight_timer> linear_flight_timer_;

    mcast_client_process (ba::io_service& ios, udp_endpoint_t& local_if, udp_endpoint_t& mgroup, int ttl, crypto_buf_t& iv, crypto_buf_t& key, stats_message_client_processor& message_processor) ;

public:
    typedef boost::shared_ptr<mcast_client_process> pointer;

    bool cancel () ;

    static boost::shared_ptr<mcast_client_process> create (ba::io_service& ios, udp_endpoint_t& local_if, udp_endpoint_t& mgroup, int ttl, crypto_buf_t& iv, crypto_buf_t& key, stats_message_client_processor& message_processor) ;

    void handle_client_service_request (const bs::error_code& ec, const crypto_error& eec) ;

    void handle_linear_flight_timer (const bs::error_code& ec) ;

    void handle_recv_service_replies (const bs::error_code& ec, const crypto_error& eec) ;

    void init_components () ;

    virtual  ~mcast_client_process () ;
 template<typename Handler >
    void adapt_timer(Handler handler,const bs::error_code& ec)
    {
        CryptoPP::Exception eec(CryptoPP::Exception::NOT_IMPLEMENTED,std::string("Success"));
        if(!ec.value())
            handler(ba::error::timed_out,eec);
        else handler(ec,eec);
    }
 template<typename Handler >
      bool exec(bt::millisec flight_base, bt::millisec flight_increment, int nitems, stats_message_t& req, std::vector<stats_message_t>& replies, Handler handler) {
        try{
            LOG(INFO)<<name_<<"::"<<__FUNCTION__;
            DLOG(INFO)<<"flight_base:\t"<<flight_base.total_milliseconds();
            DLOG(INFO)<<"flight_increment:\t"<<flight_increment.total_milliseconds();
            DLOG(INFO)<<"nitems:\t"<<nitems ;

            phdl::error_handler_t
                bound_handle_linear_flight_timer = boost::bind(&mcast_client_process::handle_linear_flight_timer,shared_from_this(),_1);
            phdl::system_crypto_handler_t
                bound_handle_client_service_request = boost::bind(&mcast_client_process::handle_client_service_request,shared_from_this(),
                                                                  ba::placeholders::error,_2);
             phdl::system_crypto_handler_t
                bound_handle_recv_service_replies = boost::bind(&mcast_client_process::handle_recv_service_replies,shared_from_this(),_1,_2);


            phdl::error_handler_t
                    top_timer=boost::bind(&mcast_client_process::adapt_timer<Handler>,shared_from_this(),boost::protect(handler),_1);
            phdl::error_handler_t composed_timer=phdl::branch_compose(bound_handle_linear_flight_timer,top_timer,{});
            pcmd::action_t op_linear_flight_timer = pcmd::wrap(linear_flight_timer_,flight_base,flight_increment,nitems,composed_timer);

            phdl::system_crypto_handler_t
                    composed_recv=phdl::branch_compose(bound_handle_recv_service_replies,handler,{});
            pcmd::action_t op_recv_service_replies = pcmd::wrap(recv_service_replies_,boost::ref(replies),composed_recv);

            phdl::system_crypto_handler_t
                    composed_send=phdl::branch_compose(bound_handle_client_service_request,handler,op_recv_service_replies,{0});
            pcmd::action_t op_client_service_request = pcmd::wrap(client_service_request_,req,composed_send);


            return pcmd::invoke(op_linear_flight_timer)&&pcmd::invoke(op_client_service_request);
        }
        catch(std::exception &e){
           LOG(WARNING)<<name_<<"::"<<__FUNCTION__<<":"<<e.what();
           cancel();
           return false;
        }
        
    }
};

}//end namespace service
}//end namespace components

#endif /*#ifdef mcast_client_process_hpp*/
